/*++
*
* The file contains the routines to create a device and handle ioctls
*
-- */

#include "precomp.h"


#pragma NDIS_INIT_FUNCTION(FilterRegisterDevice)


_IRQL_requires_max_(PASSIVE_LEVEL)
	NDIS_STATUS
	FilterRegisterDevice(
	VOID
	)
{
	NDIS_STATUS            Status = NDIS_STATUS_SUCCESS;
	UNICODE_STRING         DeviceName;
	UNICODE_STRING         DeviceLinkUnicodeString;
	PDRIVER_DISPATCH       DispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1];
	NDIS_DEVICE_OBJECT_ATTRIBUTES   DeviceAttribute;
	PFILTER_DEVICE_EXTENSION        FilterDeviceExtension;
	UNICODE_STRING			DefaultSDDLString;

	DEBUGP(DL_TRACE, "==>FilterRegisterDevice\n");

	NdisZeroMemory(DispatchTable, (IRP_MJ_MAXIMUM_FUNCTION+1) * sizeof(PDRIVER_DISPATCH));

	DispatchTable[IRP_MJ_CREATE] = FilterDispatch;
	DispatchTable[IRP_MJ_CLEANUP] = FilterDispatch;
	DispatchTable[IRP_MJ_CLOSE] = FilterDispatch;
	DispatchTable[IRP_MJ_DEVICE_CONTROL] = FilterDeviceIoControl;


	NdisInitUnicodeString(&DeviceName, NTDEVICE_STRING);
	NdisInitUnicodeString(&DeviceLinkUnicodeString, LINKNAME_STRING);
	NdisInitUnicodeString(&DefaultSDDLString,L"D:P(A;;GA;;;SY)(A;;GA;;;BG)(A;;GA;;;IU)(A;;GA;;;RC)");
	
	
	//
	// Create a device object and register our dispatch handlers
	//
	NdisZeroMemory(&DeviceAttribute, sizeof(NDIS_DEVICE_OBJECT_ATTRIBUTES));

	DeviceAttribute.Header.Type = NDIS_OBJECT_TYPE_DEVICE_OBJECT_ATTRIBUTES;
	DeviceAttribute.Header.Revision = NDIS_DEVICE_OBJECT_ATTRIBUTES_REVISION_1;
	DeviceAttribute.Header.Size = sizeof(NDIS_DEVICE_OBJECT_ATTRIBUTES);
	DeviceAttribute.DefaultSDDLString = &DefaultSDDLString;
	DeviceAttribute.DeviceName = &DeviceName;
	DeviceAttribute.SymbolicName = &DeviceLinkUnicodeString;
	DeviceAttribute.MajorFunctions = &DispatchTable[0];
	DeviceAttribute.ExtensionSize = sizeof(FILTER_DEVICE_EXTENSION);

	Status = NdisRegisterDeviceEx(
		FilterDriverHandle,
		&DeviceAttribute,
		&DeviceObject,
		&NdisFilterDeviceHandle
		);


	if (Status == NDIS_STATUS_SUCCESS)
	{
		FilterDeviceExtension = NdisGetDeviceReservedExtension(DeviceObject);

		FilterDeviceExtension->Signature = 'FTDR';
		FilterDeviceExtension->Handle = FilterDriverHandle;
	}


	DEBUGP(DL_TRACE, "<==FilterRegisterDevice: %x\n", Status);

	return (Status);

}

_IRQL_requires_max_(PASSIVE_LEVEL)
	VOID
	FilterDeregisterDevice(
	VOID
	)

{
	if (NdisFilterDeviceHandle != NULL)
	{
		NdisDeregisterDeviceEx(NdisFilterDeviceHandle);
	}

	NdisFilterDeviceHandle = NULL;

}

_Use_decl_annotations_
	NTSTATUS
	FilterDispatch(
	PDEVICE_OBJECT       DeviceObject,
	PIRP                 Irp
	)
{
	PIO_STACK_LOCATION       IrpStack;
	NTSTATUS                 Status = STATUS_SUCCESS;

	UNREFERENCED_PARAMETER(DeviceObject);

	IrpStack = IoGetCurrentIrpStackLocation(Irp);

	switch (IrpStack->MajorFunction)
	{
	case IRP_MJ_CREATE:
		break;

	case IRP_MJ_CLEANUP:
		break;

	case IRP_MJ_CLOSE:
		break;

	default:
		break;
	}

	Irp->IoStatus.Status = Status;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);

	return Status;
}

_Use_decl_annotations_
	NTSTATUS
	FilterDeviceIoControl(
	PDEVICE_OBJECT        DeviceObject,
	PIRP                  Irp
	)
{
	PIO_STACK_LOCATION          IrpSp;
	NTSTATUS                    Status = STATUS_SUCCESS;
	PFILTER_DEVICE_EXTENSION    FilterDeviceExtension;
	PUCHAR                      InputBuffer;
	PUCHAR                      OutputBuffer;
	ULONG                       InputBufferLength, OutputBufferLength;
	PLIST_ENTRY                 Link;
	PUCHAR                      pInfo;
	ULONG                       InfoLength = 0;
	PMS_FILTER                  pFilter = NULL;
	BOOLEAN                     bFalse = FALSE;


	UNREFERENCED_PARAMETER(DeviceObject);


	IrpSp = IoGetCurrentIrpStackLocation(Irp);

	if (IrpSp->FileObject == NULL)
	{
		return(STATUS_UNSUCCESSFUL);
	}


	FilterDeviceExtension = (PFILTER_DEVICE_EXTENSION)NdisGetDeviceReservedExtension(DeviceObject);

	ASSERT(FilterDeviceExtension->Signature == 'FTDR');

	Irp->IoStatus.Information = 0;

	switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
	{
	case IOCTL_FILTER_SET_NETWORK_STATUS_CONFIG:
		SetConutsToZero();
		DbgPrint("!!!IOCTL_FILTER_SET_NETWORK_STATUS_CONFIG called.\r\n");
		break;

	case IOCTL_FILTER_SET_NETWORK_BLOCKALL:
		SetQzjNdisStatus(QZJFILTER_COUNTS_STATUS_BLOCKALL);
		DbgPrint("!!!IOCTL_FILTER_SET_NETWORK_BLOCKALL called.\r\n");
		break;

	case IOCTL_FILTER_SET_NETWORK_ALLOWALL:
		SetQzjNdisStatus(QZJFILTER_COUNTS_STATUS_ALLOWALL);
		DbgPrint("!!!QZJFILTER_COUNTS_STATUS_ALLOWALL called.\r\n");
		break;

	case IOCTL_FILTER_SET_NETWORK_DEFAULT:
		SetQzjNdisStatus(QZJFILTER_COUNTS_STATUS_HEARTBEAT);
		DbgPrint("!!!IOCTL_FILTER_SET_NETWORK_DEFAULT called.\r\n");
		break;

	case IOCTL_FILTER_RESTART_ALL:
		break;

	case IOCTL_FILTER_RESTART_ONE_INSTANCE:
		InputBuffer = OutputBuffer = (PUCHAR)Irp->AssociatedIrp.SystemBuffer;
		InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

		pFilter = filterFindFilterModule (InputBuffer, InputBufferLength);

		if (pFilter == NULL)
		{

			break;
		}

		NdisFRestartFilter(pFilter->FilterHandle);

		break;

	case IOCTL_FILTER_ENUERATE_ALL_INSTANCES:

		InputBuffer = OutputBuffer = (PUCHAR)Irp->AssociatedIrp.SystemBuffer;
		InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
		OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;


		pInfo = OutputBuffer;

		FILTER_ACQUIRE_LOCK(&FilterListLock, bFalse);

		Link = FilterModuleList.Flink;

		while (Link != &FilterModuleList)
		{
			pFilter = CONTAINING_RECORD(Link, MS_FILTER, FilterModuleLink);


			InfoLength += (pFilter->FilterModuleName.Length + sizeof(USHORT));

			if (InfoLength <= OutputBufferLength)
			{
				*(PUSHORT)pInfo = pFilter->FilterModuleName.Length;
				NdisMoveMemory(pInfo + sizeof(USHORT),
					(PUCHAR)(pFilter->FilterModuleName.Buffer),
					pFilter->FilterModuleName.Length);

				pInfo += (pFilter->FilterModuleName.Length + sizeof(USHORT));
			}

			Link = Link->Flink;
		}

		FILTER_RELEASE_LOCK(&FilterListLock, bFalse);
		if (InfoLength <= OutputBufferLength)
		{

			Status = NDIS_STATUS_SUCCESS;
		}
		//
		// Buffer is small
		//
		else
		{
			Status = STATUS_BUFFER_TOO_SMALL;
		}
		break;


	default:
		break;
	}

	Irp->IoStatus.Status = Status;
	Irp->IoStatus.Information = InfoLength;

	IoCompleteRequest(Irp, IO_NO_INCREMENT);

	return Status;


}


_IRQL_requires_max_(DISPATCH_LEVEL)
	PMS_FILTER
	filterFindFilterModule(
	_In_reads_bytes_(BufferLength)
	PUCHAR                   Buffer,
	_In_ ULONG                    BufferLength
	)
{

	PMS_FILTER              pFilter;
	PLIST_ENTRY             Link;
	BOOLEAN                  bFalse = FALSE;

	FILTER_ACQUIRE_LOCK(&FilterListLock, bFalse);

	Link = FilterModuleList.Flink;

	while (Link != &FilterModuleList)
	{
		pFilter = CONTAINING_RECORD(Link, MS_FILTER, FilterModuleLink);

		if (BufferLength >= pFilter->FilterModuleName.Length)
		{
			if (NdisEqualMemory(Buffer, pFilter->FilterModuleName.Buffer, pFilter->FilterModuleName.Length))
			{
				FILTER_RELEASE_LOCK(&FilterListLock, bFalse);
				return pFilter;
			}
		}

		Link = Link->Flink;
	}

	FILTER_RELEASE_LOCK(&FilterListLock, bFalse);
	return NULL;
}
